home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / OCFSRC.PAK / OCREG.CPP < prev    next >
C/C++ Source or Header  |  1997-05-06  |  20KB  |  565 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectComponents
  3. // Copyright (c) 1994, 1997 by Borland International, All Rights Reserved
  4. //
  5. // $Revision:   2.9  $
  6. //
  7. //   OLE Registration implementation
  8. //----------------------------------------------------------------------------
  9. #include <ocf/pch.h>
  10. #if !defined(OCF_OCREG_H)
  11. # include <ocf/ocreg.h>
  12. #endif
  13. #if !defined(OCF_APPDESC_H)
  14. # include <ocf/appdesc.h>
  15. #endif
  16. #if !defined(CLASSLIB_POINTER_H)
  17. # include <classlib/pointer.h>
  18. #endif
  19. #include <shellapi.h>
  20. #include <string.h>
  21. #include <stdlib.h>
  22.  
  23. DIAG_DEFINE_GROUP(OcDll, true, 1);
  24. DIAG_DECLARE_GROUP(OcRefCount);
  25.  
  26. #if defined(BI_NAMESPACE)
  27. namespace OCF {
  28. #endif
  29.  
  30. #if defined(BI_APP_DLL)
  31.   extern TRegistrar* DllRegistrar;
  32. #endif
  33.  
  34. //----------------------------------------------------------------------------
  35. // Internal registration template table and registration item key table
  36. //
  37.  
  38. //
  39. // Registration template table, ordering determines sequence of registration
  40. //  Also, these are all based on HKEY_CLASSES_ROOT
  41. //  Note: the parameter table is dependent on template indices in this table
  42. //
  43. static const char* OcRegTemplates[] = {
  44. #if defined(BI_PLAT_WIN32)
  45. /* 001 */ "CLSID\\<clsid>\\<serverctx>Server32 = <debugger> <path> <cmdline><extraopt>",
  46. #else
  47. /* 001 */ "CLSID\\<clsid>\\<serverctx>Server = <debugger> <path> <cmdline><extraopt>",
  48. #endif
  49. /* 002 */ "CLSID\\<clsid>\\ProgID = <progid>",
  50. /* 003 */ "CLSID\\<clsid> = <description>",
  51. /* 004 */ "CLSID\\<clsid>\\DefaultIcon = <path>,<iconindex>",
  52. #if defined(BI_PLAT_WIN32)
  53. /* 005 */ "CLSID\\<clsid>\\InprocHandler32 = <handler>",
  54. #else
  55. /* 005 */ "CLSID\\<clsid>\\InprocHandler = <handler>",
  56. #endif
  57. /* 006 */ "<progid>\\CLSID = <clsid>",
  58. /* 007 */ "<progid> = <description>",
  59.  
  60. /* 010 */ "<progid>\\protocol\\StdFileEditing\\verb\\0 = <verb0>",
  61. /* 011 */ "<progid>\\protocol\\StdFileEditing\\verb\\1 = <verb1>",
  62. /* 012 */ "<progid>\\protocol\\StdFileEditing\\verb\\2 = <verb2>",
  63. /* 013 */ "<progid>\\protocol\\StdFileEditing\\verb\\3 = <verb3>",
  64. /* 014 */ "<progid>\\protocol\\StdFileEditing\\verb\\4 = <verb4>",
  65. /* 015 */ "<progid>\\protocol\\StdFileEditing\\verb\\5 = <verb5>",
  66. /* 016 */ "<progid>\\protocol\\StdFileEditing\\verb\\6 = <verb6>",
  67. /* 017 */ "<progid>\\protocol\\StdFileEditing\\verb\\7 = <verb7>",
  68.  
  69. /* 020 */ "CLSID\\<clsid>\\Verb\\0 = <verb0>,<verb0opt>",
  70. /* 021 */ "CLSID\\<clsid>\\Verb\\1 = <verb1>,<verb1opt>",
  71. /* 022 */ "CLSID\\<clsid>\\Verb\\2 = <verb2>,<verb2opt>",
  72. /* 023 */ "CLSID\\<clsid>\\Verb\\3 = <verb3>,<verb3opt>",
  73. /* 024 */ "CLSID\\<clsid>\\Verb\\4 = <verb4>,<verb4opt>",
  74. /* 025 */ "CLSID\\<clsid>\\Verb\\5 = <verb5>,<verb5opt>",
  75. /* 026 */ "CLSID\\<clsid>\\Verb\\6 = <verb6>,<verb6opt>",
  76. /* 027 */ "CLSID\\<clsid>\\Verb\\7 = <verb7>,<verb7opt>",
  77.  
  78. /* 030 */ "CLSID\\<clsid>\\DataFormats\\GetSet\\0 = <format0>",
  79. /* 031 */ "CLSID\\<clsid>\\DataFormats\\GetSet\\1 = <format1>",
  80. /* 032 */ "CLSID\\<clsid>\\DataFormats\\GetSet\\2 = <format2>",
  81. /* 033 */ "CLSID\\<clsid>\\DataFormats\\GetSet\\3 = <format3>",
  82. /* 034 */ "CLSID\\<clsid>\\DataFormats\\GetSet\\4 = <format4>",
  83. /* 035 */ "CLSID\\<clsid>\\DataFormats\\GetSet\\5 = <format5>",
  84. /* 036 */ "CLSID\\<clsid>\\DataFormats\\GetSet\\6 = <format6>",
  85. /* 037 */ "CLSID\\<clsid>\\DataFormats\\GetSet\\7 = <format7>",
  86.  
  87. /* 040 */ "CLSID\\<clsid>\\MiscStatus = <aspectall>",
  88. /* 041 */ "CLSID\\<clsid>\\MiscStatus\\1 = <aspectcontent>",
  89. /* 042 */ "CLSID\\<clsid>\\MiscStatus\\2 = <aspectthumbnail>",
  90. /* 043 */ "CLSID\\<clsid>\\MiscStatus\\4 = <aspecticon>",
  91. /* 044 */ "CLSID\\<clsid>\\MiscStatus\\8 = <aspectdocprint>",
  92. /* 045 */ "CLSID\\<clsid>\\AuxUserType\\2 = <menuname>",
  93. /* 046 */ "CLSID\\<clsid>\\AuxUserType\\3 = <appname>",
  94. /* 047 */ "CLSID\\<clsid>\\Insertable",
  95.  
  96. /* 050 */ "<permid> = <permname>",
  97. /* 051 */ "<permid>\\CLSID = <clsid>",
  98. /* 052 */ "<permid>\\CurVer = <progid>",
  99. /* 053 */ "CLSID\\<clsid>\\VersionIndependentProgID = <permid>",
  100.  
  101. /* 054 */ "CLSID\\<clsid>\\Version = <version>",
  102. /* 055 */ "CLSID\\<clsid>\\DataFormats\\DefaultFile = <filefmt>",
  103. /* 056 */ "CLSID\\<clsid>\\Ole1Class = <progid>",        
  104. /* 057 */ ".<extension> = <progid>",
  105.  
  106. /* 060 */ "<progid>\\Shell\\Print\\Command = <path> %1",
  107. /* 061 */ "<progid>\\Shell\\Open\\Command = <path> %1",
  108. /* 062 */ "<progid>\\protocol\\StdFileEditing\\server = <debugger> <path><extraopt>",
  109. /* 063 */ "<progid>\\Insertable",
  110.  
  111. // Following entries are specific to controls
  112. //
  113.  
  114. /* 064 */ "CLSID\\<clsid>\\Control",
  115. /* 065 */ "CLSID\\<clsid>\\ToolBoxBitmap32 = <path>,<toolbmpindex>",
  116.  
  117.           0,
  118. };
  119.  
  120. //
  121. // Registration parameter table, ordering is arbitrary, parameters lowercase
  122. //
  123. static TRegParamList::TEntry OcRegParams[] = {
  124.   {"clsid",             0, ""                },// GUID standard string form
  125.   {"progid",            0, "\001\002\003\005\006\007"},// A unique name
  126.   {"insertable",        0, "\046\047\062\063"},// Defined to publish server
  127.   {"control",           0, "\064\065"        },// Defined to publish control
  128.   {"usage",  ocrSingleUse, ""                },// Class factory registration
  129.   {"description",       0, ""                },// Human readable, 40 chars max
  130. #if defined(BI_PLAT_WIN32)
  131.   {"handler", "ole32.dll", "\005"            },// Inproc handler
  132. #else
  133.   {"handler",  "ole2.dll", "\005"            },// Inproc handler
  134. #endif
  135.   {"serverctx",         0, "\001"            },// "Local"(EXE) or "Inproc"(DLL)
  136.   {"path",              0, ""                },// OC defaults to load path
  137.   {"cmdline",          "", ""                },// /Automation if app class
  138.   {"debugger",         "", ""                },// Debugger to invoke server
  139.   {"permid",            0, "\050\051\053"    },// Version independent clsid
  140.   {"permname",          0, "\052"            },// Version independent progid
  141.   {"iconindex",       "0", "\004"            },// Zero-based resource icon
  142.   {"toolbmpindex",    "1", "\065"            },// Index of resource bitmap for palette
  143.   {"menuname",         "", "\045"            },// 15 characters maximum
  144.   {"appname",           0, ""                },// AppName, AuxUserType/3
  145.   {"verb0",             0, "\010\020"        },// Name of primary verb
  146.   {"verb1",             0, "\011\021"        },
  147.   {"verb2",             0, "\012\022"        },
  148.   {"verb3",             0, "\013\023"        },
  149.   {"verb4",             0, "\014\024"        },
  150.   {"verb5",             0, "\015\025"        },
  151.   {"verb6",             0, "\016\026"        },
  152.   {"verb7",             0, "\017\027"        },
  153.   {"verb8",             0, "\018\028"        },
  154.   {"verb0opt",      "0,2", "\020"            },// From REGVERBOPT macro
  155.   {"verb1opt",      "0,2", "\021"            },
  156.   {"verb2opt",      "0,2", "\022"            },
  157.   {"verb3opt",      "0,2", "\023"            },
  158.   {"verb4opt",      "0,2", "\024"            },
  159.   {"verb5opt",      "0,2", "\025"            },
  160.   {"verb6opt",      "0,2", "\026"            },
  161.   {"verb7opt",      "0,2", "\027"            },
  162.   {"verb8opt",      "0,2", "\028"            },
  163.   {"format0",           0, "\030"            },// From REGFORMAT macro
  164.   {"format1",           0, "\031"            },
  165.   {"format2",           0, "\032"            },
  166.   {"format3",           0, "\033"            },
  167.   {"format4",           0, "\034"            },
  168.   {"format5",           0, "\035"            },
  169.   {"format6",           0, "\036"            },
  170.   {"format7",           0, "\037"            },
  171.   {"format8",           0, "\038"            },
  172.   {"filefmt",           0, "\055"            },// Default file format name
  173.   {"aspectall",       "0", "\040"            },// Option flags for all aspects
  174.   {"aspectcontent",     0, "\041"            },// Option flags for content view
  175.   {"aspectthumbnail",   0, "\042"            },// Option flags thumbnail view
  176.   {"aspecticon",        0, "\043"            },// Option flags for icon view
  177.   {"aspectdocprint",    0, "\044"            },// Option flags docprint view
  178.   {"extension",         0, "\057\060\061"    },// Extension for shell loading
  179.   {"version",           0, "\054"            },// App/typelib version string
  180.   {"helpdir",           0, ""                },// Help directory for typehelp
  181.   {"typehelp",          0, ""                },// Help file for type library
  182.   {"language",          0, ""                },// Set internally from func arg
  183.   {"docflags",        "0", ""                },
  184.   {"directory",         0, ""                },
  185.   {"docfilter",         0, ""                },
  186.   {"debugclsid",        0, ""/*INTERNAL GEN*/},// Internal,NOT USER SPECIFIED
  187.   {"extraopt",         "", ""/*INTERNAL USE*/},// Cmdline debug/non-debug flag
  188.   {"debugprogid",       0, ""                },// Define to force debug reg
  189.   {"debugdesc",         0, ""                },// Different string for debug
  190.   {0,                   0, 0                 },// End
  191. };
  192.  
  193. //
  194. // Generate OLE registration file image to an output stream
  195. //
  196. // Process a given regInfo table to produce an ascii registration list out to
  197. // an ostream. Arguments are:
  198. //  regInfo  - main registration list to work from
  199. //  module   - hinstance of program module for 'path' & 'serverctx' entries
  200. //  out      - output stream to receive reg entry lines
  201. //  lang     - language id for 'language' entry & string translation
  202. //  filter   - optional template restricting filter
  203. //  defaults - optional reg entries processed before main list
  204. //  overrides- optional reg entries processed after main list
  205. //
  206. long OcRegisterClass(TRegList& regInfo, HINSTANCE module, ostream& out,
  207.                      TLangId lang, char* filter, TRegItem* defaults,
  208.                      TRegItem* overrides)
  209. {
  210.   // Use OCF global registration templates & parameters
  211.   //
  212.   TRegSymbolTable symbolTable(TRegKey::ClassesRoot, OcRegTemplates, OcRegParams);
  213.  
  214.   // Initialize the symbol table
  215.   //
  216.   symbolTable.Init(filter);
  217.  
  218.   // Check for language defaulted to system or user configuration &
  219.   // assign language parameter based on TLocaleString's setting
  220.   //
  221.   if (lang == LangSysDefault)
  222.     lang = TLocaleString::SystemDefaultLangId;
  223.   else if (lang == LangUserDefault)
  224.     lang = TLocaleString::UserDefaultLangId;
  225.  
  226.   int langIdx = symbolTable.Params.Find("language");
  227.   char langBuf[10];
  228.   wsprintf(langBuf, "%X", lang);
  229.   symbolTable.Params.Value(langIdx) = langBuf;
  230.  
  231.   // Assign path parameter initially to module load path of the given HINSTANCE
  232.   //
  233.   const int pathSize = 512;
  234.   TAPointer<char> path = new char[pathSize];
  235.   ::GetModuleFileName(module, path, pathSize);
  236.   symbolTable.Params.Value(symbolTable.Params.Find("path")) = path;
  237.  
  238.   // Assign server context based on whether it is an EXE or a DLL
  239.   //
  240.   // NOTE: Assumes that this code is linked into server's module
  241.   //
  242.   {
  243.   int svrIdx = symbolTable.Params.Find("serverctx");
  244.   if (svrIdx >= 0)
  245. #if defined (BI_PTR_0_32)
  246.     if (::GetModuleHandle(0) == module) // Check instance handle for 32bit EXE
  247.       symbolTable.Params.Value(svrIdx) = "Local";
  248.     else
  249.       symbolTable.Params.Value(svrIdx) = "Inproc";
  250. #else
  251.     if (((unsigned)module | 1) == _SS)  // Check instance handle for 16bit EXE
  252.       symbolTable.Params.Value(svrIdx) = "Local";
  253.     else
  254.       symbolTable.Params.Value(svrIdx) = "Inproc";
  255. #endif
  256.   }
  257.  
  258.   // Build params from the 3 lists provided in this order:
  259.   //
  260.   //  0: defaults list (defaults)
  261.   //  1: user list of parameters and custom keys (regList)
  262.   //  2: and overrides list (overrides)
  263.   //
  264.   symbolTable.UpdateParams(lang, defaults);
  265.   symbolTable.UpdateParams(lang, regInfo.Items);
  266.   symbolTable.UpdateParams(lang, overrides);
  267.  
  268.   symbolTable.StreamOut(regInfo.Items, out);
  269.  
  270.   // Decode & return document template flags
  271.   //
  272.   int i = symbolTable.Params.Find("docflags");
  273.   if (i >= 0)
  274.     return atol(symbolTable.Params.Value(i));
  275.   return 0;
  276. }
  277.  
  278. //
  279. // Unregister application or class from registration database
  280. //
  281. // These params are the only ones needed to unregister an OLE program or class
  282. //
  283. int OcUnregisterClass(TRegList& regInfo, TRegItem* overrides)
  284. {
  285.   static TRegistry::TUnregParams unregParams[] = {
  286.     { '.', "extension",   &TRegKey::ClassesRoot },
  287.     {  0,  "debugclsid",  &TRegKey::ClassesRootClsid },
  288.     {  0,  "debugprogid", &TRegKey::ClassesRoot },
  289.     {  0,  "clsid",       &TRegKey::ClassesRootClsid },
  290.     {  0,  "progid",      &TRegKey::ClassesRoot },
  291.     {  0,  "permid",      &TRegKey::ClassesRoot },
  292.     {  0,   0,            0 },
  293.   };
  294.   return TRegistry::Unregister(regInfo, unregParams, overrides);
  295. }
  296.  
  297. //----------------------------------------------------------------------------
  298. // Separate debugging registration for application and documents
  299. // Overrides non-debug values with values from debug keys
  300. //
  301.  
  302. //
  303. //
  304. //
  305. TRegItem OcRegNoDebug[] = { {"debugger", {""}}, {0,{0}} };
  306. TRegItem OcRegNotDll[]  = { {"cmdline", {""}}, {"debugger", {""}}, {0,{0}} };
  307.  
  308. //
  309. // Filters limit the templates used when setting up debug registration
  310. //
  311. char AppDebugFilter[] = "\001\002\003\005\006\007";
  312. char DocDebugFilter[] = "\001\002\003\005\006\007"
  313.                         "\020\021\022\023\024\025\026\027"
  314.                         "\030\031\032\033\034\035\036\037"
  315.                         "\040\041\042\043\044\045\046\047"
  316.                         "\054\055\062\063";
  317.  
  318. //
  319. //
  320. //
  321. struct TDebugRegKey { enum { progid,        clsid,   description,   extraopt};};
  322. char* OcReplaceKeys[] =  {  "progid",      "clsid", "description", "extraopt"};
  323. char* OcDebugKeys[] = {"debugprogid", "debugclsid", "debugdesc",   "debugopt"};
  324.  
  325. //
  326. // Walk thru a reginfo list using debug entries to create a parallel non-debug
  327. // set for alternate, debug registration.
  328. // Return:
  329. //   0 - No debug registration needed / available
  330. //   1 - Debug registration using passed classid
  331. //  -1 - Debug registration using classid found in reginfo
  332. //
  333. int OcSetupDebugReg(TRegList& regInfo, TRegItem* regDebug, TLangId lang,
  334.                     char* clsid)
  335. {
  336.   char** oldKey = OcReplaceKeys;
  337.   char** newKey = OcDebugKeys;
  338.  
  339.   // Walk thru the special keys with debug alternates
  340.   //
  341.   int stat = -1;         // Initialize for regInfo-supplied clsid
  342.   for (int i = 0; i < COUNTOF(OcReplaceKeys); i++,oldKey++,newKey++,regDebug++) {
  343.     const char* value = regInfo.Lookup(*newKey, lang);
  344.  
  345.     // If not value found for a given key, supply a default if possible, else
  346.     // throw an exception.
  347.     //
  348.     if (!value) {
  349.       switch (i) {
  350.         case TDebugRegKey::progid:
  351.           return 0;                   // No debug registration if progid missing
  352.         case TDebugRegKey::extraopt:
  353.           value = " /Debug";          // Default to "/Debug" on command line
  354.           break;
  355.         case TDebugRegKey::clsid:
  356.           if (clsid) {
  357.             value = clsid;
  358.             stat = 1;                 // Flag use of supplied clsid
  359.             break;
  360.           }       // else fall through to throw exception--clsid is required
  361.         case TDebugRegKey::description:
  362.           TXRegistry::Check(1, *newKey); // incomplete debug registration
  363.       }
  364.     }
  365.     regDebug->Key   = *oldKey;         // Write normal key + debug value to
  366.     regDebug->Value = value;           // output reg list
  367.   }
  368.   regDebug->Key = 0;                   // 0-terminate reg list
  369.   return stat;
  370. }
  371.  
  372. #if defined(BI_NAMESPACE)
  373. } // namespace OCF
  374. #endif
  375.  
  376. //----------------------------------------------------------------------------
  377. // TRegistrar - Application registration manager interface class
  378. //
  379.  
  380. //
  381. //
  382. //
  383. TRegistrar* TRegistrar::RegistrarList = 0;
  384.  
  385. //
  386. //
  387. //
  388. TRegistrar::TRegistrar(TRegList& regInfo, TComponentFactory callback,
  389.                        string& cmdLine, HINSTANCE hInst)
  390. :
  391.   AppDesc(*new TAppDescriptor(regInfo, callback, cmdLine, hInst))
  392. {
  393.   Next = RegistrarList;
  394.   RegistrarList = this;
  395.   TRACEX(OcRefCount, 1, "TRegistrar() @" << (void*)this);
  396. }
  397.  
  398. //
  399. //
  400. //
  401. TRegistrar::TRegistrar(TAppDescriptor& appDesc)
  402. :
  403.   AppDesc(appDesc)
  404. {
  405.   Next = RegistrarList;
  406.   RegistrarList = this;
  407. }
  408.  
  409. //
  410. //
  411. //
  412. TRegistrar::~TRegistrar()
  413. {
  414.   // Since TRegistrars are destroyed when the module is shutdown
  415.   // we do not need to detach each registrar from the linked list
  416.   //
  417.   delete &AppDesc;
  418. }
  419.  
  420. //
  421. //
  422. //
  423. TRegistrar* TRegistrar::GetNext(TRegistrar* reg)
  424. {
  425.   return reg ? reg->Next : RegistrarList;
  426. }
  427.  
  428. //
  429. //
  430. //
  431. void far* TRegistrar::GetFactory(const GUID& clsid, const GUID far& iid)
  432. {
  433.   void far* retObj = 0;
  434.   if (clsid != AppDesc.AppClassId)
  435.     return 0;
  436.   ((IUnknown&)AppDesc).QueryInterface(iid, &retObj);
  437.   return retObj;   // QueryInterface sets to null if fails
  438. }
  439.  
  440. //
  441. //
  442. //
  443. bool TRegistrar::CanUnload()
  444. {
  445.   return static_cast<bool>(!AppDesc.IsBound());
  446. }
  447.  
  448. //
  449. //
  450. //
  451. int TRegistrar::Run()
  452. {
  453.   if (!IsOptionSet(amExeModule))
  454.     return 0;    // inproc server waits until class factory created and called
  455.   TComponentFactory factory = AppDesc.GetFactory();
  456.   if (!factory)
  457.     return 1;
  458.   if (AppDesc.IsAutomated() && IsOptionSet(amAutomation))
  459.     RegisterAppClass();
  460.   IUnknown* ifc = factory(0, GetOptions() | amRun);  // create app and run it
  461.  
  462.   // App is now running its message loop, factory may get called again by OLE
  463.   //
  464.   ifc = factory(ifc, GetOptions() | amShutdown);  // EXE finished, destroy it
  465.   if (ifc && !(GetOptions() & amServedApp))
  466.     ifc->Release();  // we own the reference count, else container released it
  467.   return 0;
  468. }
  469.  
  470. //
  471. //
  472. //
  473. void TRegistrar::Shutdown(IUnknown* releasedObj, uint32 options)
  474. {
  475.   if (!AppDesc.GetFactory())
  476.     return;
  477.   releasedObj = AppDesc.GetFactory()(releasedObj, options|amShutdown);
  478.   if (releasedObj)
  479.     releasedObj->Release();
  480. }
  481.  
  482. //----------------------------------------------------------------------------
  483. // DLL server entry points
  484. //
  485.  
  486. //
  487. // Entry point for complete registration management via command line
  488. // Don't let any exceptions blow back to OLE.
  489. //
  490. STDAPI __export DllRegisterCommand(const char far* cmdLine)
  491. {
  492.   try {
  493.     bool isDebug = false;
  494.     TRegistrar* registrar = 0;
  495.  
  496.     // Need to set up typelibrary state information in case multiple components
  497.     //
  498.     while ((registrar = TRegistrar::GetNext(registrar)) != 0) {
  499.       string cmd(cmdLine);
  500.       registrar->ProcessCmdLine(cmd);
  501.       if (registrar->IsOptionSet(amDebug))
  502.         isDebug = true;
  503.     }
  504.     if (isDebug)
  505.       __emit__(0xCC); // force debugg trap if REGISTER.EXE loaded with debugger
  506.     return HR_OK;
  507.   }
  508.   catch (...) {
  509.     return HR_FAIL;
  510.   }
  511. }
  512.  
  513. //
  514. // OLE 2.0 entry point for obtaining a class factory for a particular CLSID
  515. // Don't let any exceptions blow back to OLE.
  516. //
  517. STDAPI __export DllGetClassObject(const GUID far& clsid, const GUID far& iid,
  518.                                   void far* far* retObj)
  519. {
  520.   try {
  521.     TRegistrar* registrar = 0;
  522.     while ((registrar = TRegistrar::GetNext(registrar)) != 0) {
  523.       *retObj = registrar->GetFactory(clsid, iid);
  524.       if (*retObj)
  525.         return HR_OK;
  526.     }
  527.     return HR_FAIL;
  528.   }
  529.   catch (...) {
  530.     return HR_FAIL;
  531.   }
  532. }
  533.  
  534. //
  535. // OLE 2.0 entry point for checking if DLL has no clients and can be unloaded
  536. //
  537. STDAPI __export DllCanUnloadNow()
  538. {
  539.   TRegistrar* registrar = 0;
  540.   while ((registrar = TRegistrar::GetNext(registrar)) != 0) {
  541.     if (!registrar->CanUnload()) {
  542.       TRACEX(OcDll, 1, "DllCanUnloadNow returning HR_FALSE");
  543.       return HR_FALSE;
  544.     }
  545.   }
  546.   TRACEX(OcDll, 1, "DllCanUnloadNow returning HR_OK");
  547.   return HR_OK;
  548. }
  549.  
  550. //
  551. // OLE 2.0 entry point for registering DLL, no locale info passed
  552. //
  553. STDAPI __export DllRegisterServer()
  554. {
  555.   return DllRegisterCommand("/RegServer");
  556. }
  557.  
  558. //
  559. // OLE 2.0 entry point for unregistering DLL
  560. //
  561. STDAPI __export DllUnregisterServer()
  562. {
  563.   return DllRegisterCommand("/UnregServer");
  564. }
  565.